home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 April: Mac OS SDK / Dev.CD Apr 98 SDK1.toast / Development Kits (Disc 1) / QuickDraw 3D / RAVE SDK 1.5 MacOS / RaveDemo / MyTest.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-14  |  32.0 KB  |  1,360 lines  |  [TEXT/CWIE]

  1. #include "MyHeader.h"
  2. #include "ShieldRect.h"
  3.  
  4. //
  5.  
  6. #define textureSize 128
  7. #define textureCount 5
  8. #define maxEngines 10
  9. #define textHeight 15
  10.  
  11. #define boundrySlop 0.1
  12.  
  13. #define ClipUpper(f, upperLimit) {if((f) > (upperLimit)) (f) = (upperLimit);}
  14.  
  15. #define ClampDifuseColor(v) {ClipUpper((v)->kd_r, 1.0); ClipUpper((v)->kd_g, 1.0); ClipUpper((v)->kd_b, 1.0);}
  16.  
  17. // Local Prototypes
  18. static GWorldPtr LoadPicture(short resID);
  19. static TQAError SetTextureByNumber(MyState * state, short textureNumber);
  20. static void DrawObject(MyState *state, MyObject * object, short doShading);
  21. static void ClipZ(MyState *state, TQAVTexture * v1, TQAVTexture * v2, TQAVTexture * v3);
  22. static void ConvertTo2D(MyState *state, TQAVTexture * v1, TQAVTexture * v2, TQAVTexture * v3);
  23. static void ClipLeftBound(MyState *state, TQAVTexture * v1, TQAVTexture * v2, TQAVTexture * v3);
  24. static void ClipRightBound(MyState *state, TQAVTexture * v1, TQAVTexture * v2, TQAVTexture * v3);
  25. static void ClipTopBound(MyState *state, TQAVTexture * v1, TQAVTexture * v2, TQAVTexture * v3);
  26. static void ClipBottomBound(MyState *state, TQAVTexture * v1, TQAVTexture * v2, TQAVTexture * v3);
  27. static void MyDrawTriTexture(MyState *state, TQAVTexture * v1, TQAVTexture * v2, TQAVTexture * v3);
  28. static void MyTQAVTextureClip(TQAVTexture * v1, TQAVTexture * v2, TQAVTexture * v3, float weight);
  29. static void SetupDrawContext(MyState *state);
  30. static void RectToTQARect(Rect * r, TQARect * r2);
  31. static void DeleteDrawContext(MyState *state);
  32. static RgnHandle CalcGlobalVisRgn(MyState *state);
  33.  
  34. // vars
  35. static TQAEngine *gEngineList[maxEngines];
  36. static long gEngineCount;
  37.  
  38. static MyVector xVector = {1, 0, 0};
  39. static MyVector yVector = {0, 1, 0};
  40. MyObject ob1, ob2, ob3, ob4;
  41. TQATexture * textureList[maxEngines][textureCount];
  42.  
  43. GWorldPtr gwList[textureCount];
  44.  
  45. // Code
  46.  
  47. void UpdateMyMenus(WindowPtr w)
  48. {
  49.     MyState * state;
  50.     long x;
  51.     MenuHandle mh;
  52.     
  53.     
  54.     state = (MyState*)GetWRefCon(w);
  55.     
  56.     mh = GetMenuHandle(engineMenuID);
  57.     for(x = 0; x < gEngineCount; x++){
  58.         SetItemMark(mh, x + 1, state->engineNumber == x ? checkMark : noMark);
  59.     }
  60.  
  61.     mh = GetMenuHandle(optionsMenuID);
  62.     SetItemMark(mh, 1, state->doubleBuffer ? checkMark : noMark);
  63.     SetItemMark(mh, 2, state->noZBuffer ? checkMark : noMark);
  64.     SetItemMark(mh, 3, state->perspectiveZ ? checkMark : noMark);
  65.     SetItemMark(mh, 4, state->useMemoryDevice ? checkMark : noMark);
  66.     SetItemMark(mh, 5, state->useTriMeshes ? checkMark : noMark);
  67.  
  68.     mh = GetMenuHandle(antialiasingMenuID);
  69.     for(x = 0; x < 4; x++){
  70.         SetItemMark(mh, x + 1, state->antialiasing == x ? checkMark : noMark);
  71.     }
  72.  
  73.     mh = GetMenuHandle(textureFilterMenuID);
  74.     for(x = 0; x < 3; x++){
  75.         SetItemMark(mh, x + 1, state->textureFilter == x ? checkMark : noMark);
  76.     }
  77.  
  78.  
  79. }
  80.  
  81. static void SetEngine(MyState * state, long engineNumber)
  82. {
  83.     Str255 s;
  84.     
  85.     /*****/
  86.     
  87.     state->engineNumber = engineNumber;
  88.     state->engine = gEngineList[engineNumber];
  89.     
  90.     GetMenuItemText(GetMenuHandle(engineMenuID), engineNumber + 1, s);
  91.     SetWTitle(state->window, s);
  92. }
  93.  
  94.  
  95. void MyTestSetup(void)
  96. {    
  97.     long x;    
  98.     Str255 engineName;
  99.     long engineNameLength;
  100.     TQAEngine *engine;
  101.  
  102.     /**************/
  103.     
  104.     // build the engine menu
  105.     QAEngineEnable(kQAVendor_Apple, kQAEngine_AppleHW);
  106.     gEngineCount = 0;
  107.     for(engine = QADeviceGetFirstEngine(NULL); engine; engine = QADeviceGetNextEngine(NULL, engine)){
  108.         gEngineList[gEngineCount] = engine;
  109.         gEngineCount++;
  110.         
  111.         QAEngineGestalt(engine, kQAGestalt_ASCIINameLength, &engineNameLength);
  112.         QAEngineGestalt(engine, kQAGestalt_ASCIIName, (char *)engineName + 1);
  113.         engineName[0] = engineNameLength;
  114.         AppendMenu(GetMenuHandle(engineMenuID), engineName);
  115.     }
  116.     
  117.     for(x = 0; x < textureCount; x++){
  118.         gwList[x] = LoadPicture(141 + x);
  119.     }
  120.  
  121.     //WriteGlobe();
  122.     //WriteCylinder();
  123.     
  124.     ob1.shape = MyShapeLoad("cylinder");
  125.     MyShapeCalculateNormals(ob1.shape, 2);
  126.     ob1.backfaceCulling = 1;
  127.     ob1.alpha = 1;
  128.  
  129.     ob2.shape = MyShapeLoad("globe");
  130.     MyShapeCalculateNormals(ob2.shape, 0);
  131.     ob2.backfaceCulling = 0;
  132.     ob2.alpha = 0.5;
  133.  
  134.     ob4.shape = MyShapeLoad("die");
  135.     MyShapeCalculateNormals(ob4.shape, 0);
  136.     ob4.backfaceCulling = 1;
  137.     ob4.alpha = 1;
  138.  
  139.     ob3.shape = MyShapeLoad("floor");
  140.     MyShapeCalculateNormals(ob3.shape, 1);
  141.     ob3.alpha = 1;
  142.     
  143.     MyMatrixClear(&globalState.camera);
  144.     globalState.camera.w.z -= 7;
  145.  
  146.  
  147. }
  148.  
  149. void SetupNewWindow(void)
  150. {
  151.     MyMatrix m;
  152.     MyState *state;
  153.  
  154.     /**************/
  155.     
  156.     state = calloc(sizeof (MyState), 1);
  157.     CheckMem(state);
  158.         
  159.     state->d = 0.1;
  160.     state->h = state->d * 0.5;
  161.     state->f = 100;
  162.     state->ambient = 0.3;
  163.     state->window = GetNewCWindow(128, NULL, (WindowPtr) -1);
  164.     state->perspectiveZ = 1;
  165.     state->doubleBuffer = 1;
  166.     state->useTriMeshes = 1;
  167.     
  168.     SetPort(state->window);
  169.     TextMode(srcXor);
  170.     TextSize(9);
  171.     TextFont(monaco);
  172.     SetWRefCon(state->window, (long)state);
  173.     
  174.     SetEngine(state, 0);
  175.     SetItemMark(GetMenuHandle(engineMenuID), 1, checkMark);
  176.  
  177.     SetupDrawContext(state);
  178.  
  179.     state->lightVector = yVector;
  180.     MyMatrixSetRotateX(-0.5, &m);
  181.     MyMatrixTransformVector(&m, &state->lightVector, &state->lightVector);  // rotate the light slightly toward the camera
  182.     MyMatrixSetRotateZ(-0.5, &m);
  183.     MyMatrixTransformVector(&m, &state->lightVector, &state->lightVector);
  184.     
  185. }
  186.  
  187. void UnloadTextures(void)
  188. {
  189.     long x, y;    
  190.     TQAEngine *engine;
  191.     
  192.     /********/
  193.     
  194.     for(y = 0; y < gEngineCount; y++){
  195.         engine = gEngineList[y];
  196.         for(x = 0; x < textureCount; x++){
  197.             if(textureList[y][x]){
  198.                 QATextureDelete(engine, textureList[y][x]);
  199.             }
  200.         }
  201.     }
  202.     
  203.     for(x = 0; x < textureCount; x++){
  204.         if(gwList[x]){
  205.             DisposeGWorld(gwList[x]);
  206.         }
  207.     }
  208. }
  209.  
  210. static void DrawErrorMessage(MyState *state)
  211. {
  212.     SetPort(state->window);
  213.     EraseRect(&state->window->portRect);
  214.     if(state->errorMessage){
  215.         TETextBox(state->errorMessage, strlen(state->errorMessage), &state->window->portRect, teFlushDefault);
  216.     }
  217. }
  218.  
  219.  
  220. static void DumpTriangles(MyState * state)
  221. {
  222.     long x;
  223.     
  224.     /******/
  225.     
  226.     if(state->vList.count == 0) return; // nothing to draw
  227.     
  228.     QASubmitVerticesTexture(state->drawContext, state->vList.count, state->vList.list);
  229.     state->vList.count = 0;
  230.     
  231.     for(x = 0; x < textureCount; x++){
  232.         if(state->tList[x].count){        // make sure that there are triangles that use this texture
  233.             SetTextureByNumber(state, x);
  234.             //QASetPtr(state->drawContext, kQATag_Texture, state->textureList[x]);
  235.             QADrawTriMeshTexture(state->drawContext, state->tList[x].count, state->tList[x].list);
  236.             state->tList[x].count = 0;
  237.         }
  238.     }
  239. }
  240.  
  241.  
  242. // MyEqualRgn is about 3 times faster than EqualRgn on PPC
  243. #define MyEqualRgn(r1, r2) (!memcmp(*(r1), *(r2), (**(r1)).rgnSize))
  244.  
  245. #if 0
  246. // elapsedTime is in seconds
  247. static void MoveCamera(MyState *state, float elapsedTime)
  248. {
  249.     KeyMap theKeys;
  250.  
  251.     GetKeys(&theKeys)
  252. }
  253. #endif
  254.  
  255.  
  256. void DrawFrame(MyState *state)
  257. {
  258.     Point mousy;
  259.     MyMatrix m;
  260.     char s[200];
  261.     
  262.     UnsignedWide startTime;
  263.     UnsignedWide finishTime;
  264.     
  265.     float framesPerSecond;
  266.     
  267.     Rect r;
  268.         
  269.     /************/
  270.     
  271.     Microseconds(&startTime);
  272.     
  273.     if(!state->active){
  274.         DrawErrorMessage(state);
  275.         return;
  276.     }
  277.     
  278.     // if we are drawing to a gdevice, check to see if the visable area changed
  279.     // to make sure we don't draw over any other windows
  280.     if(!state->useMemoryDevice){
  281.         if(!MyEqualRgn(state->window->visRgn, state->visRegion)){
  282.             WindowChanged(state->window);
  283.         }
  284.     }
  285.     
  286.     SetPort(state->window); // port must be set before LocalToGlobal is called
  287.     GetMouse(&mousy);
  288.     LocalToGlobal(&mousy);
  289.  
  290.     /* the camera */
  291. #if 0
  292.     MyMatrixClear(&state->camera);
  293.     MyMatrixSetRotateY((float)mousy.h / -100, &m);
  294.     MyMatrixCat(&state->camera, &m, &state->camera);
  295.     state->camera.w.z -= (float)mousy.v / 40 + 3;
  296. #endif
  297.  
  298.     if(!globalState.stopObjects){
  299.         /* cylinder */
  300.         MyMatrixClear(&ob1.pos);
  301.         MyMatrixSetRotateY((float)TickCount() / 50, &m);
  302.         MyMatrixCat(&ob1.pos, &m, &ob1.pos);
  303.         MyMatrixSetRotateX((float)mousy.h / 200, &m);
  304.         MyMatrixCat(&ob1.pos, &m, &ob1.pos);
  305.         ob1.pos.w.z += sin((float)TickCount() / 150) * 0.5;
  306.         ob1.pos.w.y += cos((float)TickCount() / 150) * 3;
  307.  
  308.         /* globe */
  309.         MyMatrixClear(&ob2.pos);
  310.         MyMatrixSetRotateY((float)TickCount() / 75, &m);
  311.         MyMatrixCat(&ob2.pos, &m, &ob2.pos);
  312.         MyMatrixSetRotateX((float)mousy.h / 160, &m);
  313.         MyMatrixCat(&ob2.pos, &m, &ob2.pos);
  314.     //    MyMatrixScaleLocal(&ob2.pos, (sin((float)TickCount() / -160) + 1.1) * 3, &ob2.pos);
  315.         ob2.pos.w.x += sin((float)TickCount() / -160) * 3;
  316.         ob2.pos.w.y += cos((float)TickCount() / -160) * 3;
  317.         ob2.pos.w.z -= 0.2;
  318.  
  319.         /* the floor and walls */
  320.         MyMatrixClear(&ob3.pos);
  321.         ob3.pos.w.y += -1.5;
  322.         
  323.         /* the die */
  324.         MyMatrixClear(&ob4.pos);
  325.         MyMatrixSetRotateY((float)TickCount() / 100, &m);
  326.         MyMatrixCat(&ob4.pos, &m, &ob4.pos);
  327.         MyMatrixSetRotateX((float)TickCount() / 20, &m);
  328.         MyMatrixCat(&ob4.pos, &m, &ob4.pos);
  329.     }
  330.  
  331.  
  332.     if(!state->useTriMeshes){
  333.         QARenderStart(state->drawContext, NULL, NULL);
  334.     }
  335.  
  336.     state->triangleCount = 0;
  337.     DrawObject(state, &ob1, true);
  338.     DrawObject(state, &ob3, true);
  339.     DrawObject(state, &ob4, true);
  340.  
  341.     DrawObject(state, &ob2, true);  // this sould go last because it has transpearancy
  342.  
  343.     if(state->useTriMeshes){
  344.         QARenderStart(state->drawContext, NULL, NULL);
  345.         DumpTriangles(state);
  346.     }
  347.     
  348.     QARenderEnd(state->drawContext, NULL);
  349.     
  350.     if(state->useMemoryDevice){
  351.         QASync(state->drawContext);
  352.         CopyBits(PortBits(state->backBuffer), PortBits(state->window), &state->viewRect, &state->viewRect, srcCopy, NULL);
  353.     } else {
  354.         state->needsSync = true;
  355.     }
  356.     Microseconds(&finishTime);
  357.     
  358.     framesPerSecond = 1000000.0 / (finishTime.lo - startTime.lo); // subtracting will cancel out any overflow in .hi
  359.     
  360.     sprintf(s, "%7.2f fps (%hdx%hd) (TriCount=%4ld) (%2x)", 
  361.         framesPerSecond, 
  362.         state->viewRect.right - state->viewRect.left, 
  363.         state->viewRect.bottom - state->viewRect.top, 
  364.         state->triangleCount,
  365.         (int)globalState.unusedKey);
  366.     
  367.     r = state->window->portRect;
  368.     r.top = r.bottom - textHeight;
  369.     EraseRect(&r);
  370.     MoveTo(5, r.bottom - 2);
  371.     DrawText(s, 0, strlen(s));
  372. }
  373.  
  374.  
  375.  
  376.  
  377.  
  378.  
  379. void HandleOtherMenu(short menuID, short menuItem)
  380. {
  381.     WindowPtr w;
  382.     MyState * state;
  383.     short newValue;
  384.     
  385.     /*****/
  386.  
  387.     w = FrontWindow();
  388.     
  389.     if(!w) return;
  390.  
  391.     state = (MyState*)GetWRefCon(w);
  392.  
  393.     switch(menuID){
  394.     case engineMenuID:
  395.         DeleteDrawContext(state);
  396.         SetEngine(state, menuItem - 1);
  397.         SetupDrawContext(state);
  398.         break;
  399.         
  400.     case optionsMenuID:
  401.         switch(menuItem){
  402.         case 1:
  403.             newValue = state->doubleBuffer = !state->doubleBuffer;
  404.             break;
  405.         case 2:
  406.             newValue = state->noZBuffer = !state->noZBuffer;
  407.             break;
  408.         case 3:
  409.             newValue = state->perspectiveZ = !state->perspectiveZ;
  410.             break;
  411.         case 4:
  412.             newValue = state->useMemoryDevice = !state->useMemoryDevice;
  413.             break;
  414.         case 5:
  415.             newValue = state->useTriMeshes = !state->useTriMeshes;
  416.             break;
  417.         }
  418.         DeleteDrawContext(state);    
  419.         SetupDrawContext(state);
  420.         break;
  421.     case antialiasingMenuID:
  422.         DeleteDrawContext(state);
  423.         state->antialiasing = menuItem - 1;
  424.         SetupDrawContext(state);
  425.         break;
  426.     case textureFilterMenuID:
  427.         DeleteDrawContext(state);
  428.         state->textureFilter = menuItem - 1;
  429.         SetupDrawContext(state);
  430.         break;
  431.     }
  432.     
  433.     UpdateMyMenus(w);
  434. }
  435.  
  436. void WindowChanged(WindowPtr theWindow)
  437. {
  438.     MyState * state;
  439.  
  440.     ///////
  441.     
  442.     state = (MyState*)GetWRefCon(theWindow);
  443.     
  444.     DeleteDrawContext(state);    
  445.     SetupDrawContext(state);
  446. }
  447.  
  448. void ClosingWindow(WindowPtr theWindow)
  449. {
  450.     MyState * state;
  451.  
  452.     ///////
  453.     
  454.     state = (MyState*)GetWRefCon(theWindow);
  455.     DeleteDrawContext(state);
  456.     free(state);
  457. }
  458.  
  459. static GWorldPtr LoadPicture(short resID)
  460. {
  461.     PicHandle p;
  462.     GWorldPtr gw;
  463.     QDErr e;
  464.     static Rect r = {0, 0, textureSize, textureSize};
  465.     GDHandle tempGD;
  466.     CGrafPtr tempPort;
  467.     PixMapHandle pm;
  468.  
  469.     /*************/
  470.     
  471.     p = GetPicture(resID);
  472.     
  473.     e = NewGWorld(&gw, 16, &r, NULL, NULL, 0);
  474.     
  475.     if(e) return NULL;
  476.     
  477.     pm = GetGWorldPixMap(gw);
  478.     LockPixels(pm);
  479.     
  480.     GetGWorld(&tempPort, &tempGD);
  481.     SetGWorld(gw, NULL);
  482.     
  483.     EraseRect(&r);
  484.     DrawPicture(p, &r);
  485.     ReleaseResource((Handle)p);
  486.     
  487.     SetGWorld(tempPort, tempGD);
  488.     
  489.     return gw;
  490. }
  491.  
  492. static TQAError SetTextureByNumber(MyState * state, short textureNumber)
  493. {
  494.     PixMapHandle pm;
  495.     TQAImage images[1];
  496.     TQATexture * texture;
  497.     TQAError err;
  498.     
  499.     /************/
  500.     
  501.     texture = textureList[state->engineNumber][textureNumber];
  502.     if(texture == NULL){
  503.         pm = GetGWorldPixMap(gwList[textureNumber]);
  504.         
  505.         images[0].width = textureSize;
  506.         images[0].height = textureSize;
  507.         images[0].rowBytes = (**pm).rowBytes & 0x3fff;
  508.         images[0].pixmap = (**pm).baseAddr;
  509.         
  510.         err = QATextureNew(state->engine, 0, kQAPixel_RGB16, images, &texture);
  511.         if(err){
  512.             return err;
  513.         }
  514.         
  515.         textureList[state->engineNumber][textureNumber] = texture;
  516.     }
  517.  
  518.     QASetPtr(state->drawContext, kQATag_Texture, texture);
  519.  
  520. }
  521.  
  522.  
  523.  
  524.  
  525.  
  526. // see watt book p71 fig. 3.9
  527.  
  528. /*
  529. note, specular calculation is a short cut.
  530. in real life vv would be different for each point.
  531. specular is just based on normal as if it were at center of object
  532. */
  533.  
  534. static void DrawObject(MyState *state, MyObject * object, short doShading)
  535. {
  536.     MyShape * shape = object->shape;
  537.     long x, c, pn;
  538.             
  539.     MyVector v1, v2;
  540.     MyVector n; // surface normal
  541.     MyVector reflectionVector; // surface reflection vector
  542.     MyVector lightSource; // camera relative light source vector
  543.     MyVector toCamera; // view vector (from obj to cam)
  544.         
  545.     float difuse;
  546.     float specular;
  547.     
  548.     TQAVTexture verts[3];
  549.     TQAVTexture * v;
  550.     
  551.     MyMatrix r1;
  552.     
  553.     MyVector * points;
  554.     MyVector * p;
  555.     float * difs;
  556.     float * specs;
  557.     
  558.     MyTri * tri;
  559.     
  560.     long previousTexture = -1;
  561.     short backfacing;
  562.     
  563.     /***********/
  564.     
  565.  
  566.     
  567.     MyMatrixNegate(&globalState.camera, &r1);
  568.         // state->camera is the position of the camera in world space.
  569.         // r1 is now the position of the world in camera space    
  570.     MyMatrixCat(&object->pos, &r1, &r1);  // r1 is now the position of the object relative to the camera and not the world
  571.     
  572.     if(r1.w.z + shape->maxDimention < state->d) return;    // the object is completely behind the camera, dont bother drawing
  573.     
  574.     MYMALLOC(points, shape->pointCount);
  575.     for(x = 0; x < shape->pointCount; x++){
  576.         p = &points[x];
  577.         MyMatrixTransformVector(&r1, &shape->pointList[x], p);
  578.     }
  579.     
  580.     
  581.     if(doShading){
  582.         MYMALLOC(difs, shape->normalCount);
  583.         MYMALLOC(specs, shape->normalCount);
  584.         
  585.         MyMatrixNegate(&object->pos, &r1);
  586.         // r1 is world to object transform
  587.         MyMatrixRotateVector(&r1, &state->lightVector, &lightSource);    // lightSource is now the vector to the light relative to the object and not the world
  588.         MyVectorSubtract(&globalState.camera.w, &object->pos.w, &toCamera); // toCamera is object center to camera in world space
  589.         // note, this is a short cut.
  590.         // more accurate to way is to calc per vertex
  591.         MyMatrixRotateVector(&r1, &toCamera, &toCamera);    // toCamera is now the vector to the camera in object space
  592.         MyVectorNormalize(&toCamera, &toCamera);            // normalized
  593.  
  594.         // this calculates the specular value on a per normal basis
  595.         for(x = 0; x < shape->normalCount; x++){
  596.             
  597.             difuse = MyDotProduct(&lightSource, &shape->normalList[x]);
  598. //            if(difuse < 0) difuse = 0;
  599.             
  600.             MyCalculateReflection(&lightSource, &shape->normalList[x], &reflectionVector);
  601.             specular = MyDotProduct(&reflectionVector, &toCamera);
  602.             if(specular < 0){
  603.                 specular = 0;
  604.             } else {
  605.                 specular = pow(specular, 40);
  606.             }
  607.             
  608.             difs[x] = difuse;
  609.             specs[x] = specular;
  610.         }
  611.     }
  612.     
  613.     
  614.     if(doShading){
  615.         QASetInt(state->drawContext, kQATag_TextureOp, kQATextureOp_Modulate + kQATextureOp_Highlight);
  616.     } else {
  617.         QASetInt(state->drawContext, kQATag_TextureOp, 0);
  618.     }
  619.     
  620.     if(object->alpha < 1){
  621. //        state->saveTransTris = true;
  622.     }
  623.     
  624.     for(x = 0; x < shape->triangleCount; x++){
  625.         tri = &shape->triangleList[x];
  626.         
  627.  
  628.         if(object->backfaceCulling || doShading){
  629.             MyVectorSubtract(&points[tri->corner[1].pointNumber], &points[tri->corner[0].pointNumber], &v1);
  630.             MyVectorSubtract(&points[tri->corner[2].pointNumber], &points[tri->corner[0].pointNumber], &v2);
  631.             MyVectorCrossProduct(&v2, &v1, &n);
  632.             backfacing = MyDotProduct(&points[tri->corner[0].pointNumber], &n) > 0;
  633.             if(backfacing && object->backfaceCulling) continue;
  634.         }
  635.  
  636.         if(shape->normalMode == 1){
  637.             if(backfacing){
  638.                 difuse = -difs[shape->normalTable[x]];
  639.             } else {
  640.                 difuse = difs[shape->normalTable[x]];
  641.             }
  642.             if(difuse < 0) difuse = 0;
  643.             specular = specs[shape->normalTable[x]];
  644.         }
  645.         
  646.         for(c = 0; c < 3; c++){
  647.             pn = tri->corner[c].pointNumber;
  648.             v = &verts[c];
  649.             p = &points[pn];
  650.             
  651.             if(shape->normalMode == 0){
  652.                 if(backfacing){
  653.                     difuse = -difs[shape->normalTable[x * 3 + c]];
  654.                 } else {
  655.                     difuse = difs[shape->normalTable[x * 3 + c]];
  656.                 }
  657.                 if(difuse < 0) difuse = 0;
  658.                 specular = specs[shape->normalTable[x * 3 + c]];
  659.             }
  660.             
  661.             v->x = p->x;
  662.             v->y = p->y;
  663.             v->z = p->z;
  664.             v->uOverW = tri->corner[c].u;
  665.             v->vOverW = tri->corner[c].v;
  666.             
  667.             v->r = v->g = v->b = 1;
  668.             v->a = object->alpha;
  669.             
  670.             if(doShading){
  671.                 v->kd_r = v->kd_g = v->kd_b = difuse + state->ambient;
  672.                 v->ks_r = v->ks_g = v->ks_b = specular;
  673.             } else {
  674.                 v->kd_r = v->kd_g = v->kd_b = 1;
  675.                 v->ks_r = v->ks_g = v->ks_b = 0;
  676.             }
  677.             
  678.         }
  679.  
  680.         if(tri->texture != previousTexture){
  681.             if(state->useTriMeshes){
  682.                 state->currentTList = &state->tList[tri->texture];
  683.             } else {
  684.                 SetTextureByNumber(state, tri->texture);
  685.                 //QASetPtr(state->drawContext, kQATag_Texture, state->textureList[tri->texture]);
  686.             }
  687.             previousTexture = tri->texture;
  688.         }
  689.         
  690.         ClipZ(state, &verts[0], &verts[1], &verts[2]);
  691.         
  692.     }
  693.  
  694.     
  695.     free(points);
  696.     if(doShading){
  697.         free(difs);
  698.         free(specs); 
  699.     }
  700. }
  701.  
  702. #define CLIPX(p1, p2, p3, xBound) MyTQAVTextureClip(p1, p2, p3, (p2->x - xBound) / (p2->x - p1->x))
  703. #define CLIPY(p1, p2, p3, yBound) MyTQAVTextureClip(p1, p2, p3, (p2->y - yBound) / (p2->y - p1->y))
  704. #define CLIPZ(p1, p2, p3, zBound) MyTQAVTextureClip(p1, p2, p3, (p2->z - zBound) / (p2->z - p1->z))
  705.  
  706.  
  707. static void ClipZ(MyState *state, TQAVTexture * v1, TQAVTexture * v2, TQAVTexture * v3)
  708. {
  709.     TQAVTexture ta, tb;
  710.     float bound = state->d + boundrySlop;
  711.     
  712.     /***/
  713.     
  714.     if(v1->z < bound){
  715.         if(v2->z < bound){
  716.             if(v3->z < bound){
  717.                 // all points are out of bounds, draw nothing
  718.                 return;
  719.             } else {
  720.                 // 1 & 2 are out
  721.                 CLIPZ(v1, v3, &ta, bound);
  722.                 CLIPZ(v2, v3, &tb, bound);
  723.                 ConvertTo2D(state, &ta, &tb, v3);
  724.             }
  725.         } else {
  726.             if(v3->z < bound){
  727.                 // 1 & 3 are out
  728.                 CLIPZ(v1, v2, &ta, bound);
  729.                 CLIPZ(v3, v2, &tb, bound);
  730.                 ConvertTo2D(state, &ta, &tb, v2);
  731.             } else {
  732.                 // 1 is out
  733.                 CLIPZ(v1, v2, &ta, bound);
  734.                 CLIPZ(v1, v3, &tb, bound);
  735.                 ConvertTo2D(state, &ta, v2, v3);
  736.                 ConvertTo2D(state, &tb, &ta, v3);
  737.             }
  738.  
  739.         }
  740.     } else {
  741.         if(v2->z < bound){
  742.             if(v3->z < bound){
  743.                 // 2 & 3 are out
  744.                 CLIPZ(v2, v1, &ta, bound);
  745.                 CLIPZ(v3, v1, &tb, bound);
  746.                 ConvertTo2D(state, &ta, &tb, v1);
  747.                 return;
  748.             } else {
  749.                 // 2 is out
  750.                 CLIPZ(v2, v1, &ta, bound);
  751.                 CLIPZ(v2, v3, &tb, bound);
  752.                 ConvertTo2D(state, &ta, v1, v3);
  753.                 ConvertTo2D(state, &tb, &ta, v3);
  754.             }
  755.         } else {
  756.             if(v3->z < bound){
  757.                 // 3 is out
  758.                 CLIPZ(v3, v1, &ta, bound);
  759.                 CLIPZ(v3, v2, &tb, bound);
  760.                 ConvertTo2D(state, &ta, v1, v2);
  761.                 ConvertTo2D(state, &tb, &ta, v2);
  762.             } else {
  763.                 // all are in
  764.                 ConvertTo2D(state, v1, v2, v3);
  765.             }
  766.         }
  767.     }
  768. }
  769.  
  770.  
  771. static void ConvertTo2D(MyState *state, TQAVTexture * v1, TQAVTexture * v2, TQAVTexture * v3)
  772. {
  773.     float iw;
  774.     TQAVTexture * v;    
  775.     TQAVTexture verts[3];    // must use a local copy because values are modified
  776.     long c;
  777.     
  778.     float pixelConversion = (state->d / state->h) * (-state->viewWidth / 2);
  779.     
  780.     verts[0] = *v1;
  781.     verts[1] = *v2;
  782.     verts[2] = *v3;
  783.  
  784.     for(c = 0; c < 3; c++){
  785.         v = &verts[c];
  786.  
  787.         iw = 1.0 / v->z;
  788.         
  789.         
  790.         
  791.         v->x = v->x * iw * pixelConversion + (state->viewWidth/2);
  792.         v->y = v->y * iw * pixelConversion + (state->viewHeight/2);
  793.         v->z = (v->z * (state->f / (state->f - state->d)) + (-state->f * state->d / (state->f - state->d))) * iw;
  794. //        v->z = v->z / state->f;
  795. //        v->z = 0.5;
  796.         
  797.         v->invW = iw;
  798. //        v->invW = 1.0;
  799.         v->uOverW *= iw;
  800.         v->vOverW *= iw;            
  801.     }
  802.     
  803.     ClipLeftBound(state, &verts[0], &verts[1], &verts[2]);
  804. }
  805.  
  806.  
  807. static void ClipLeftBound(MyState *state, TQAVTexture * v1, TQAVTexture * v2, TQAVTexture * v3)
  808. {
  809.     TQAVTexture ta, tb;
  810.     float bound = 0 + boundrySlop;
  811.     
  812.     /***/
  813.     
  814.     if(v1->x < bound){
  815.         if(v2->x < bound){
  816.             if(v3->x < bound){
  817.                 // all points are out of bounds, draw nothing
  818.                 return;
  819.             } else {
  820.                 // 1 & 2 are out
  821.                 CLIPX(v1, v3, &ta, bound);
  822.                 CLIPX(v2, v3, &tb, bound);
  823.                 ClipRightBound(state, &ta, &tb, v3);
  824.             }
  825.         } else {
  826.             if(v3->x < bound){
  827.                 // 1 & 3 are out
  828.                 CLIPX(v1, v2, &ta, bound);
  829.                 CLIPX(v3, v2, &tb, bound);
  830.                 ClipRightBound(state, &ta, &tb, v2);
  831.             } else {
  832.                 // 1 is out
  833.                 CLIPX(v1, v2, &ta, bound);
  834.                 CLIPX(v1, v3, &tb, bound);
  835.                 ClipRightBound(state, &ta, v2, v3);
  836.                 ClipRightBound(state, &tb, &ta, v3);
  837.             }
  838.  
  839.         }
  840.     } else {
  841.         if(v2->x < bound){
  842.             if(v3->x < bound){
  843.                 // 2 & 3 are out
  844.                 CLIPX(v2, v1, &ta, bound);
  845.                 CLIPX(v3, v1, &tb, bound);
  846.                 ClipRightBound(state, &ta, &tb, v1);
  847.                 return;
  848.             } else {
  849.                 // 2 is out
  850.                 CLIPX(v2, v1, &ta, bound);
  851.                 CLIPX(v2, v3, &tb, bound);
  852.                 ClipRightBound(state, &ta, v1, v3);
  853.                 ClipRightBound(state, &tb, &ta, v3);
  854.             }
  855.         } else {
  856.             if(v3->x < bound){
  857.                 // 3 is out
  858.                 CLIPX(v3, v1, &ta, bound);
  859.                 CLIPX(v3, v2, &tb, bound);
  860.                 ClipRightBound(state, &ta, v1, v2);
  861.                 ClipRightBound(state, &tb, &ta, v2);
  862.             } else {
  863.                 // all are in
  864.                 ClipRightBound(state, v1, v2, v3);
  865.             }
  866.         }
  867.     }
  868. }
  869.  
  870.  
  871. static void ClipRightBound(MyState *state, TQAVTexture * v1, TQAVTexture * v2, TQAVTexture * v3)
  872. {
  873.     TQAVTexture ta, tb;
  874.     float bound = state->viewWidth - boundrySlop;
  875.     /***/
  876.     
  877.     if(v1->x > bound){
  878.         if(v2->x > bound){
  879.             if(v3->x > bound){
  880.                 // all points are out of bounds, draw nothing
  881.                 return;
  882.             } else {
  883.                 // 1 & 2 are out
  884.                 CLIPX(v1, v3, &ta, bound);
  885.                 CLIPX(v2, v3, &tb, bound);
  886.                 ClipTopBound(state, &ta, &tb, v3);
  887.             }
  888.         } else {
  889.             if(v3->x > bound){
  890.                 // 1 & 3 are out
  891.                 CLIPX(v1, v2, &ta, bound);
  892.                 CLIPX(v3, v2, &tb, bound);
  893.                 ClipTopBound(state, &ta, &tb, v2);
  894.             } else {
  895.                 // 1 is out
  896.                 CLIPX(v1, v2, &ta, bound);
  897.                 CLIPX(v1, v3, &tb, bound);
  898.                 ClipTopBound(state, &ta, v2, v3);
  899.                 ClipTopBound(state, &tb, &ta, v3);
  900.             }
  901.  
  902.         }
  903.     } else {
  904.         if(v2->x > bound){
  905.             if(v3->x > bound){
  906.                 // 2 & 3 are out
  907.                 CLIPX(v2, v1, &ta, bound);
  908.                 CLIPX(v3, v1, &tb, bound);
  909.                 ClipTopBound(state, &ta, &tb, v1);
  910.                 return;
  911.             } else {
  912.                 // 2 is out
  913.                 CLIPX(v2, v1, &ta, bound);
  914.                 CLIPX(v2, v3, &tb, bound);
  915.                 ClipTopBound(state, &ta, v1, v3);
  916.                 ClipTopBound(state, &tb, &ta, v3);
  917.             }
  918.         } else {
  919.             if(v3->x > bound){
  920.                 // 3 is out
  921.                 CLIPX(v3, v1, &ta, bound);
  922.                 CLIPX(v3, v2, &tb, bound);
  923.                 ClipTopBound(state, &ta, v1, v2);
  924.                 ClipTopBound(state, &tb, &ta, v2);
  925.             } else {
  926.                 // all are in
  927.                 ClipTopBound(state, v1, v2, v3);
  928.             }
  929.         }
  930.     }
  931. }
  932.  
  933. static void ClipTopBound(MyState *state, TQAVTexture * v1, TQAVTexture * v2, TQAVTexture * v3)
  934. {
  935.     TQAVTexture ta, tb;
  936.     float bound = 0 + boundrySlop;
  937.     /***/
  938.     
  939.     if(v1->y < bound){
  940.         if(v2->y < bound){
  941.             if(v3->y < bound){
  942.                 // all points are out of bounds, draw nothing
  943.                 return;
  944.             } else {
  945.                 // 1 & 2 are out
  946.                 CLIPY(v1, v3, &ta, bound);
  947.                 CLIPY(v2, v3, &tb, bound);
  948.                 ClipBottomBound(state, &ta, &tb, v3);
  949.             }
  950.         } else {
  951.             if(v3->y < bound){
  952.                 // 1 & 3 are out
  953.                 CLIPY(v1, v2, &ta, bound);
  954.                 CLIPY(v3, v2, &tb, bound);
  955.                 ClipBottomBound(state, &ta, &tb, v2);
  956.             } else {
  957.                 // 1 is out
  958.                 CLIPY(v1, v2, &ta, bound);
  959.                 CLIPY(v1, v3, &tb, bound);
  960.                 ClipBottomBound(state, &ta, v2, v3);
  961.                 ClipBottomBound(state, &tb, &ta, v3);
  962.             }
  963.  
  964.         }
  965.     } else {
  966.         if(v2->y < bound){
  967.             if(v3->y < bound){
  968.                 // 2 & 3 are out
  969.                 CLIPY(v2, v1, &ta, bound);
  970.                 CLIPY(v3, v1, &tb, bound);
  971.                 ClipBottomBound(state, &ta, &tb, v1);
  972.                 return;
  973.             } else {
  974.                 // 2 is out
  975.                 CLIPY(v2, v1, &ta, bound);
  976.                 CLIPY(v2, v3, &tb, bound);
  977.                 ClipBottomBound(state, &ta, v1, v3);
  978.                 ClipBottomBound(state, &tb, &ta, v3);
  979.             }
  980.         } else {
  981.             if(v3->y < bound){
  982.                 // 3 is out
  983.                 CLIPY(v3, v1, &ta, bound);
  984.                 CLIPY(v3, v2, &tb, bound);
  985.                 ClipBottomBound(state, &ta, v1, v2);
  986.                 ClipBottomBound(state, &tb, &ta, v2);
  987.             } else {
  988.                 // all are in
  989.                 ClipBottomBound(state, v1, v2, v3);
  990.             }
  991.         }
  992.     }
  993. }
  994.  
  995. static void ClipBottomBound(MyState *state, TQAVTexture * v1, TQAVTexture * v2, TQAVTexture * v3)
  996. {
  997.     TQAVTexture ta, tb;
  998.     float bound = state->viewHeight - boundrySlop;
  999.     /***/
  1000.     
  1001.     if(v1->y > bound){
  1002.         if(v2->y > bound){
  1003.             if(v3->y > bound){
  1004.                 // all points are out of bounds, draw nothing
  1005.                 return;
  1006.             } else {
  1007.                 // 1 & 2 are out
  1008.                 CLIPY(v1, v3, &ta, bound);
  1009.                 CLIPY(v2, v3, &tb, bound);
  1010.                 MyDrawTriTexture(state, &ta, &tb, v3);
  1011.             }
  1012.         } else {
  1013.             if(v3->y > bound){
  1014.                 // 1 & 3 are out
  1015.                 CLIPY(v1, v2, &ta, bound);
  1016.                 CLIPY(v3, v2, &tb, bound);
  1017.                 MyDrawTriTexture(state, &ta, &tb, v2);
  1018.             } else {
  1019.                 // 1 is out
  1020.                 CLIPY(v1, v2, &ta, bound);
  1021.                 CLIPY(v1, v3, &tb, bound);
  1022.                 MyDrawTriTexture(state, &ta, v2, v3);
  1023.                 MyDrawTriTexture(state, &tb, &ta, v3);
  1024.             }
  1025.  
  1026.         }
  1027.     } else {
  1028.         if(v2->y > bound){
  1029.             if(v3->y > bound){
  1030.                 // 2 & 3 are out
  1031.                 CLIPY(v2, v1, &ta, bound);
  1032.                 CLIPY(v3, v1, &tb, bound);
  1033.                 MyDrawTriTexture(state, &ta, &tb, v1);
  1034.                 return;
  1035.             } else {
  1036.                 // 2 is out
  1037.                 CLIPY(v2, v1, &ta, bound);
  1038.                 CLIPY(v2, v3, &tb, bound);
  1039.                 MyDrawTriTexture(state, &ta, v1, v3);
  1040.                 MyDrawTriTexture(state, &tb, &ta, v3);
  1041.             }
  1042.         } else {
  1043.             if(v3->y > bound){
  1044.                 // 3 is out
  1045.                 CLIPY(v3, v1, &ta, bound);
  1046.                 CLIPY(v3, v2, &tb, bound);
  1047.                 MyDrawTriTexture(state, &ta, v1, v2);
  1048.                 MyDrawTriTexture(state, &tb, &ta, v2);
  1049.             } else {
  1050.                 // all are in
  1051.                 MyDrawTriTexture(state, v1, v2, v3);
  1052.             }
  1053.         }
  1054.     }
  1055. }
  1056.  
  1057.  
  1058. static void AppendToVectorList(VList * list, TQAVTexture * v1, TQAVTexture * v2, TQAVTexture * v3)
  1059. {
  1060.     if(list->count + 3 > list->bufferSize){
  1061.         list->bufferSize += 200;
  1062.         // to do: error checking
  1063.         list->list = realloc(list->list, sizeof (*list->list) * list->bufferSize);
  1064.         CheckMem(list->list);
  1065.     }
  1066.  
  1067.     list->list[list->count] = *v1;
  1068.     list->list[list->count + 1] = *v2;
  1069.     list->list[list->count + 2] = *v3;
  1070.     list->count += 3;
  1071.     
  1072. }
  1073.  
  1074. static void AppendToTriangleList(TList * list, long vertexIndex)
  1075. {
  1076.     if(list->count + 1 > list->bufferSize){
  1077.         list->bufferSize += 200;
  1078.         // to do: error checking
  1079.         list->list = realloc(list->list, sizeof (*list->list) * list->bufferSize);
  1080.         CheckMem(list->list);
  1081.     }
  1082.  
  1083.     list->list[list->count].triangleFlags = 0;
  1084.     list->list[list->count].vertices[0] = vertexIndex;
  1085.     list->list[list->count].vertices[1] = vertexIndex + 1;
  1086.     list->list[list->count].vertices[2] = vertexIndex + 2;
  1087.     list->count += 1;
  1088.     
  1089. }
  1090.  
  1091. static void MyDrawTriTexture(MyState *state, TQAVTexture * v1, TQAVTexture * v2, TQAVTexture * v3)
  1092. {
  1093.     
  1094.     ClampDifuseColor(v1);
  1095.     ClampDifuseColor(v2);
  1096.     ClampDifuseColor(v3);
  1097.     
  1098.     state->triangleCount++;
  1099.  
  1100.     if(state->useTriMeshes){
  1101.         if(state->saveTransTris){
  1102.             
  1103.         } else {
  1104.             AppendToTriangleList(state->currentTList, state->vList.count);
  1105.             AppendToVectorList(&state->vList, v1, v2, v3);
  1106.         }
  1107.     } else {
  1108.         QADrawTriTexture(state->drawContext, v1, v2, v3, 0);
  1109.     }
  1110. }
  1111.  
  1112. static void MyTQAVTextureClip(TQAVTexture * v1, TQAVTexture * v2, TQAVTexture * v3, float weight)
  1113. {
  1114.     float weight2 = 1.0 - weight;
  1115.     
  1116.     /***/
  1117.     
  1118.     v3->x = v1->x * weight + v2->x * weight2;
  1119.     v3->y = v1->y * weight + v2->y * weight2;
  1120.     v3->z = v1->z * weight + v2->z * weight2;
  1121.     
  1122.     v3->invW = v1->invW * weight + v2->invW * weight2;
  1123.     
  1124.     v3->r = v1->r * weight + v2->r * weight2;
  1125.     v3->g = v1->g * weight + v2->g * weight2;
  1126.     v3->b = v1->b * weight + v2->b * weight2;
  1127.     v3->a = v1->a * weight + v2->a * weight2;
  1128.     
  1129.     v3->uOverW = v1->uOverW * weight + v2->uOverW * weight2;
  1130.     v3->vOverW = v1->vOverW * weight + v2->vOverW * weight2;
  1131.     
  1132.     v3->kd_r = v1->kd_r * weight + v2->kd_r * weight2;
  1133.     v3->kd_g = v1->kd_g * weight + v2->kd_g * weight2;
  1134.     v3->kd_b = v1->kd_b * weight + v2->kd_b * weight2;
  1135.     
  1136.     v3->ks_r = v1->ks_r * weight + v2->ks_r * weight2;
  1137.     v3->ks_g = v1->ks_g * weight + v2->ks_g * weight2;
  1138.     v3->ks_b = v1->ks_b * weight + v2->ks_b * weight2;
  1139. }
  1140.  
  1141.  
  1142. static pascal void MyShieldRectNotifyProc(SInt16 left, SInt16 top, SInt16 right, SInt16 bottom, SInt32 refCon)
  1143. {
  1144. #pragma unused(left, top, right, bottom)
  1145.  
  1146.     MyState *state;
  1147.  
  1148.     /***********/
  1149.     
  1150.     state = (MyState *)refCon;
  1151.     
  1152.     if(state->needsSync){
  1153.         state->needsSync = false;
  1154.         QASync(state->drawContext);
  1155.     }
  1156. }
  1157.  
  1158.  
  1159.  
  1160. static void SetupDrawContext(MyState *state)
  1161. {
  1162.     TQADevice myDevice;
  1163.     TQAError err;
  1164.     Rect r, gr;
  1165.     TQARect globalRect;
  1166.     
  1167.     unsigned long flags;
  1168.     
  1169.     QDErr e;
  1170.     PixMapHandle pm;
  1171.     GDHandle gd;
  1172.     TQAClip theClip;
  1173.     TQAClip *theClipParm;
  1174.     RgnHandle clipRegion = NULL;
  1175.  
  1176.     /*************/
  1177.     
  1178.     SetPort(state->window);  // required for LocalToGlobal();
  1179.     
  1180.     // r.top, r.left must be 0,0 for now
  1181.     r = state->window->portRect;
  1182.     r.bottom -= textHeight;
  1183.     
  1184.     state->viewRect = r;
  1185.     state->viewHeight = r.bottom - r.top;
  1186.     state->viewWidth = r.right - r.left;
  1187.  
  1188.     gr = r;
  1189.     
  1190.     if(state->useTriMeshes){
  1191.         // to do: check for fail
  1192.         state->tList = calloc(sizeof (TList), textureCount);
  1193.         CheckMem(state->tList);
  1194.     }
  1195.     
  1196.     if(state->useMemoryDevice){
  1197.         e = NewGWorld(&state->backBuffer, 16, &r, NULL, NULL, keepLocal);
  1198.         if(e){
  1199.             state->errorMessage = "Error in QADrawContextNew, can't create GWorld";
  1200.             state->active = 0;
  1201.             goto end;
  1202.         }
  1203.         pm = GetGWorldPixMap(state->backBuffer);
  1204.         e = LockPixels(pm);
  1205.         myDevice.deviceType = kQADeviceMemory;
  1206.         myDevice.device.memoryDevice.rowBytes = (**pm).rowBytes & 0x3fff;
  1207.         myDevice.device.memoryDevice.pixelType = kQAPixel_ARGB16;  // apple pci hardware engine cannot draw into a kQAPixel_RGB16
  1208.         myDevice.device.memoryDevice.width = r.right;
  1209.         myDevice.device.memoryDevice.height = r.bottom;
  1210.         myDevice.device.memoryDevice.baseAddr = (**pm).baseAddr;
  1211.         
  1212.         theClipParm = NULL;
  1213.     } else {
  1214.         LocalToGlobal(TopLeft(&gr));
  1215.         LocalToGlobal(BottomRight(&gr));
  1216.         
  1217.         gd = GetMaxDevice(&gr);
  1218.  
  1219.         myDevice.deviceType = kQADeviceGDevice;
  1220.         myDevice.device.gDevice = gd;
  1221.         
  1222.         r = (**gd).gdRect;
  1223.         
  1224. /*
  1225.         if(gr.left < r.left || gr.top < r.top || gr.bottom > r.bottom || gr.right > r.right){
  1226.             state->errorMessage = "Error in QADrawContextNew, the window is not entirely contained inside a gDevice";
  1227.             state->active = 0;
  1228.             goto end;
  1229.         }
  1230. */
  1231.     
  1232.         state->visRegion = NewRgn();
  1233.         CopyRgn(state->window->visRgn, state->visRegion);
  1234.  
  1235.         clipRegion = CalcGlobalVisRgn(state);
  1236.         
  1237.         if(clipRegion){
  1238.             theClip.clipType = kQAClipRgn;
  1239.             theClip.clip.clipRgn = clipRegion;
  1240.             theClipParm = &theClip;
  1241.         } else {
  1242.             theClipParm = NULL;
  1243.         }
  1244.     }
  1245.         
  1246.     RectToTQARect(&gr, &globalRect);
  1247.  
  1248.     flags = 0;
  1249.     if(state->doubleBuffer) flags += kQAContext_DoubleBuffer;
  1250.     if(state->noZBuffer) flags += kQAContext_NoZBuffer;
  1251.     
  1252.     
  1253.     // note: if a clipping region is given then the apple software engine does double buffering even if you dont tell it to.
  1254.     err = QADrawContextNew(&myDevice, &globalRect, theClipParm, state->engine, flags, &state->drawContext);
  1255.         
  1256.     if(err){
  1257.         state->errorMessage = "Error in QADrawContextNew";
  1258.     } else {
  1259.         //RegisterShieldRect(&gr, MyShieldRectNotifyProc, (long)state, &state->shieldRectCookie);
  1260.  
  1261.         QASetInt(state->drawContext, kQATag_PerspectiveZ, state->perspectiveZ ? kQAPerspectiveZ_On : kQAPerspectiveZ_Off);
  1262.         QASetInt(state->drawContext, kQATag_TextureFilter, state->textureFilter);
  1263.         QASetInt(state->drawContext, kQATag_Antialias, state->antialiasing);
  1264.         QASetFloat(state->drawContext, kQATag_ColorBG_a, 0);
  1265.         QASetFloat(state->drawContext, kQATag_ColorBG_r, 0.2);
  1266.         QASetFloat(state->drawContext, kQATag_ColorBG_g, 0.5);
  1267.         QASetFloat(state->drawContext, kQATag_ColorBG_b, 1);
  1268.     }
  1269.     
  1270.     state->active = (err == kQANoErr);
  1271. end:
  1272.  
  1273.     if(clipRegion) DisposeRgn(clipRegion);
  1274.  
  1275.     if(!state->active){
  1276.         DrawErrorMessage(state);
  1277.     }
  1278. }
  1279.  
  1280.  
  1281. static void RectToTQARect(Rect * r, TQARect * r2)
  1282. {
  1283.     r2->top = r->top;
  1284.     r2->left = r->left;
  1285.     r2->bottom = r->bottom;
  1286.     r2->right = r->right;
  1287. }
  1288.  
  1289.  
  1290. static void DeleteDrawContext(MyState *state)
  1291. {
  1292.     long x;
  1293.     
  1294.     /*******/
  1295.     
  1296.     if(state->drawContext){
  1297.         QASync(state->drawContext); // make sure all drawing is completed
  1298.                 
  1299.         if(state->tList){
  1300.             for(x = 0; x < textureCount; x++){
  1301.                 free(state->tList[x].list);
  1302.             }
  1303.             free(state->tList);
  1304.             state->tList = NULL;
  1305.         }
  1306.         
  1307.         if(state->vList.list){
  1308.             free(state->vList.list);
  1309.             state->vList.list = NULL;
  1310.             state->vList.bufferSize = 0;
  1311.         }
  1312.         
  1313.         if(state->backBuffer) DisposeGWorld(state->backBuffer);
  1314.         if(state->visRegion) DisposeRgn(state->visRegion);
  1315.         
  1316.         QADrawContextDelete(state->drawContext);
  1317.         
  1318.         if(state->shieldRectCookie){
  1319.             UnregisterShieldRect(state->shieldRectCookie);
  1320.             state->shieldRectCookie = 0;
  1321.         }
  1322.     }
  1323. }
  1324.  
  1325.  
  1326. static RgnHandle CalcGlobalVisRgn(MyState * state)
  1327. {
  1328.     RgnHandle rgn1, rgn2;
  1329.     Point offset;
  1330.     
  1331.     /*********/
  1332.     
  1333.     offset.h = offset.v = 0;
  1334.  
  1335.     SetPort(state->window);
  1336.     LocalToGlobal(&offset);
  1337.     
  1338.     rgn1 = NewRgn();
  1339.     rgn2 = NewRgn();
  1340.     RectRgn(rgn1, &state->viewRect);
  1341.     SectRgn(state->window->visRgn, rgn1, rgn2);
  1342.     
  1343.     if(EqualRgn(rgn1, rgn2)){ // if the regions are equal then no clipping is required
  1344.         DisposeRgn(rgn2);
  1345.         rgn2 = NULL;
  1346.     } else {                // the regions are not equal.
  1347.         OffsetRgn(rgn2, offset.h, offset.v);  // translate the region to global coordinates
  1348.     }
  1349.     DisposeRgn(rgn1);        // we are done with region 1
  1350.     
  1351.     return rgn2;
  1352. }
  1353.  
  1354.  
  1355.  
  1356.  
  1357.  
  1358.  
  1359.  
  1360.